import { Component, OnInit, ViewChild } from '@angular/core';
import { _HttpClient, DrawerHelper, SettingsService } from '@delon/theme';
import { NzFormatEmitEvent, NzModalRef, NzModalService, NzNotificationService } from 'ng-zorro-antd';
import { replaceKeysDeep, applyCC } from '@shared';
import { STComponent, STColumn, STData, STColumnTag, STColumnBadge } from '@delon/abc';
import { UserInfoModalComponent } from './edit/user-modal.component';
import { zip, BehaviorSubject, Subscription, Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { DataSource, CollectionViewer } from '@angular/cdk/collections';

const BADGE_STATUS: STColumnBadge = {
  '0': { text: '正常', color: 'success' },
  '1': { text: '锁定', color: 'error' },
};

interface ItemData {
  roleId: string;
  roleName: string;
  roleCode: string;
  roleDesc: string;
}

/**
 * 用户管理
 */
@Component({
  selector: 'user-list',
  templateUrl: './user-list.component.html',
  styles: [
    `
      .ant-list-item:hover {
        background-color: #f9f9f9;
        cursor: pointer;
      }
    `,
  ],
})
export class UserListComponent implements OnInit {
  auth_btn_add = false;
  auth_btn_edit = false;
  auth_btn_del = false;
  auth_btn_reset = false;
  auth_btn_lock = false;

  treeType: 'group' | 'role' = 'group';
  ds = null;
  tags2 = [];

  /**
   * 部门树控件搜索
   */
  searchValue = '';
  /**
   * 部门树节点集合
   */
  nodes = [];
  /**
   * 角色列表
   */
  roles = [];
  /**
   * 部门树加载状态
   */
  loading = false;
  // 节点树映射
  mapShortToLong = {
    id: 'key',
    name: 'title',
  };
  /**
   * 表格控件
   */
  @ViewChild('st', { static: true }) private st: STComponent;
  /**
   * 表格搜索条件对象
   */
  params: any = {};
  /**
   * 数据源
   */
  url = '/cf/admin/user/page';
  /**
   * 定义表格要显示的列
   */
  columns: STColumn[] = applyCC([
    { title: '账号', index: 'username' },
    { title: '名称', index: 'name', width: 150 },
    { title: '手机号', index: 'phone', ccChecked: false },
    { title: '角色', render: 'roles', index: 'roleList' },
    { title: '是否锁定', index: 'lockFlag', type: 'badge', badge: BADGE_STATUS },
    { title: '所属部门', index: 'deptName', ccChecked: false },
    { title: '创建日期', index: 'createTime', type: 'date' },
    { title: '更新日期', index: 'updateTime', type: 'date', ccChecked: false },
    {
      ccDisabled: true,
      title: '操作',
      buttons: [
        {
          text: '修改',
          type: 'drawer',
          drawer: {
            title: '修改角色',
            size: 450,
            component: UserInfoModalComponent,
          },
          click: 'load',
          iif: (item: STColumn) => this.auth_btn_edit,
        },
        {
          text: '删除',
          type: 'del',
          pop: {
            title: '确定删除用户？',
            okType: 'danger',
          },
          click: (record, _modal, comp) => {
            this.http.delete(`/cf/admin/user/${record.userId}`).subscribe(res => {
              if (res.status === 200) {
                this.notice.success('成功', `成功删除【${record.username}】`);
                comp!.load();
              }
            });
          },
          iif: (item: STColumn) => {
            return this.auth_btn_del && item.username !== 'admin';
          },
        },
        {
          text: '更多',
          children: [
            {
              text: record => (record.lockFlag === '1' ? `解锁` : `锁定`),
              click: (record, _modal, comp) => {
                this.http
                  .post(`/cf/admin/user/updatelock/${record.username}?islock=${record.lockFlag === '0' ? '1' : '0'}`)
                  .subscribe(res => {
                    if (res.status === 200) {
                      this.notice.success('成功', `${record.lockFlag === '1' ? '【解锁】' : '【锁定】'}成功`);
                      comp!.load();
                    }
                  });
              },
              iif: (item: STColumn) => this.auth_btn_lock,
            },
            {
              text: '重置密码',
              type: 'del',
              pop: {
                title: '重置用户密码为1111？',
                okType: 'danger',
              },
              click: (record, _modal, comp) => {
                this.http.post(`/cf/admin/user/resetpwd/${record.username}`).subscribe(res => {
                  if (res.status === 200) {
                    this.notice.success('成功', '重置成功');
                  }
                });
              },
              iif: (item: STColumn) => this.auth_btn_reset,
            },
          ],
        },
      ],
    },
  ]);

  constructor(
    public http: _HttpClient,
    private notice: NzNotificationService,
    private drawer: DrawerHelper,
    private settings: SettingsService,
  ) {}

  ngOnInit(): void {
    this.auth_btn_add = this.settings.user.permissions.sys_user_add;
    this.auth_btn_edit = this.settings.user.permissions.sys_user_edit;
    this.auth_btn_del = this.settings.user.permissions.sys_user_del;
    this.auth_btn_reset = this.settings.user.permissions.sys_user_reset;
    this.auth_btn_lock = this.settings.user.permissions.sys_user_lock;

    this.loadDeptTree();
    this.http.get<{ data: { total: number } }>(`/cf/admin/role/page?current=1&size=10`).subscribe(res => {
      // tslint:disable-next-line: no-use-before-declare
      this.ds = new RoleDataSource(this.http, res.data.total);
    });
  }

  /**
   * 加载部门树
   */
  loadDeptTree() {
    this.loading = true;
    const api = [this.http.get(`/cf/admin/dept/tree`)];
    zip(...api)
      .pipe(
        catchError(([deptTree]) => {
          return [deptTree];
        }),
      )
      .subscribe(([deptTree]) => {
        if (deptTree.status === 200) {
          this.nodes = [];
          const o: [] = replaceKeysDeep(deptTree.data, this.mapShortToLong);
          o.forEach(r => {
            this.nodes.push(r);
          });
        }
        this.loading = false;
      });
  }

  /**
   * 打开添加对话框
   */
  openAddDiglog() {
    this.drawer
      .create('添加用户', UserInfoModalComponent, null, { size: 450 })
      .subscribe(() => this.st.load(1, this.params));
  }

  /**
   * 部门树控件点击处理
   */
  nzEvent(event: NzFormatEmitEvent): void {
    if (event.eventName === 'click') {
      if (event.node.isSelected) {
        this.params.deptId = event.node.key;
      } else {
        this.params.deptId = '';
      }
      this.st.load(1, this.params);
    }
  }

  switchTreeType(type: 'group' | 'role') {
    this.treeType = type;
  }

  onVirualItemClick(item) {
    const length = this.tags2.filter(t => t.roleId === item.roleId).length;
    if (length === 0) {
      this.tags2.push(item);
      if (!this.params.role) {
        this.params.role = [];
      }
      this.params.role.push(item.roleId);
      if (this.params.role && this.params.role.length !== 0) {
        this.params.roleId = "'" + this.params.role.join("','") + "'";
      } else {
        this.params.roleId = '';
      }
      this.st.load(1, this.params);
    }
  }

  onClose(item) {
    this.tags2 = this.tags2.filter(t => !(t.roleId === item.roleId));
    this.params.role = this.params.role.filter(t => t !== item.roleId);
    if (this.params.role && this.params.role.length !== 0) {
      this.params.roleId = "'" + this.params.role.join("','") + "'";
    } else {
      this.params.roleId = '';
    }
    this.st.load(1, this.params);
  }
}

/**
 * 角色列表数据源
 */
class RoleDataSource extends DataSource<ItemData> {
  private length;
  private pageSize = 10;
  private cachedData;
  private fetchedPages;
  private dataStream;
  private subscription;

  constructor(private http: _HttpClient, total: number) {
    super();
    this.length = total;
    this.cachedData = Array.from<ItemData>({ length: this.length });
    this.fetchedPages = new Set<number>();
    this.dataStream = new BehaviorSubject<ItemData[]>(this.cachedData);
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
    this.subscription = new Subscription();
  }

  connect(collectionViewer: CollectionViewer): Observable<ItemData[]> {
    this.subscription.add(
      collectionViewer.viewChange.subscribe(range => {
        const startPage = this.getPageForIndex(range.start);
        const endPage = this.getPageForIndex(range.end - 1);
        for (let i = startPage; i <= endPage; i++) {
          this.fetchPage(i);
        }
      }),
    );
    return this.dataStream;
  }

  disconnect(): void {
    this.subscription.unsubscribe();
  }

  private getPageForIndex(index: number): number {
    return Math.floor(index / this.pageSize);
  }

  private fetchPage(page: number): void {
    if (this.fetchedPages.has(page)) {
      return;
    }
    this.fetchedPages.add(page);

    this.http
      .get<{ data: { records: ItemData[] } }>(`/cf/admin/role/page?current=${page + 1}&size=${this.pageSize}`)
      .subscribe(res => {
        this.cachedData.splice(page * this.pageSize, this.pageSize, ...res.data.records);
        this.dataStream.next(this.cachedData);
      });
  }
}
